package pkg16b_eca.SQL.Tables;

import java.util.ArrayList;
import java.util.HashMap;
import pkg16b_eca.IntPoints;
import pkg16b_eca.SQL.Query;
import pkg16b_eca.data.validate.Person;
import pkg16b_eca.data.validate.Text;
import se.oru.informatik.InformatikException;

// Note: Felstavning på skadepelare_forslagen_roll i databasen > skade<s>pelare
public class SQLSkadespelare extends Query {

    public SQLSkadespelare() throws InformatikException {}

    /**
     * Insert a Skådespelare into a database.
     */
    public void insert(final String strNamn, final String strHarfarg, final String strKon, final String strOgonfarg, final int intAlder, final int intLangd, final int intVikt, final int intAID) {
        String query = "insert into skadespelare (SID, NAMN, KON, ALDER, LANGD, VIKT, HARFARG, OGONFARG, AID) values ("
                + SQLGetAutoIncrement("skadespelare", "SID") + ", '" + Text.getSafeSpecialCharacters(strNamn) + "', " + Person.getKon(strKon).ordinal() + ", " + intAlder + ", " + intLangd + ", " + intVikt + ", '" + strHarfarg + "', '" + strOgonfarg + "', " + intAID + ");";
        SQLInsert(query);
    }
    
    /**
     * Update a Skådespelare in a database.
     */
    public void update(final int intSID, final String strNamn, final String strHarfarg, final String strKon, final String strOgonfarg, final int intAlder, final int intLangd, final int intVikt, final int intAID) {
        String query = "update skadespelare set "
                + "namn='" + Text.getSafeSpecialCharacters(strNamn) + "', "
                + "kon=" + Person.getKon(strKon).ordinal() + ", "
                + "alder=" + intAlder + ", "
                + "langd=" + intLangd + ", "
                + "vikt=" + intVikt + ", "
                + "harfarg='" + strHarfarg + "', "
                + "ogonfarg='" + strOgonfarg + "', "
                + "AID=" + intAID + " "
                + "where SID=" + intSID;
        SQLUpdate(query);
    }

    /**
     * Delete a Skådespelare from a database.
     */
    public void delete(final int intSID) {
        String query = "delete from skadespelare where SID=" + intSID;
        SQLDelete(query);
    }
    
    /**
     * Checks if a skådespelare exists in the database.
     */
    public boolean exists(final String SName) {
        String query = SQLSelect("select namn from skadespelare where namn = '" + SName + "'");
        return !query.isEmpty();
    }
    
    /**
     * Checks if a skådespelare exists in the database.
     */
    public boolean exists(final int SID) {
        String query = SQLSelect("select SID from skadespelare where SID = '" + SID + "'");
        return !query.isEmpty();
    }

    /**
     * Usage Example : Se vilka skådespelare det finns Variables used: al =
     * ArrayList ArrayList<String> al = SQL.getSkadespelare().getSkadespelare();
     * for (String s : al) { System.out.println(s); }
     */
    public ArrayList<String> getSkadespelare() {
        return SQLSelectList("select namn from skadespelare");
    }
    
    /** Select a skådespelares namn from an ID. */
    public String getSkadespelareNamn(int SID) {
        return SQLSelect("select skadespelare.namn from skadespelare where skadespelare.sid=" + SID);
    }
    
    /** Select a skådespelares ID from a name. */
    public int getSkadespelareSID(String name) {
        return Text.parseNumber(SQLSelect("select skadespelare.sid from skadespelare where skadespelare.namn = '" + name + "'"));
    }

    /**
     * Usage Example : Se vilka attribut en skådespelare har Variables used: hm
     * = HashMap HashMap<String, String> hm =
     * SQL.getSkadespelare().getAttribut("Ebba-Louise Flink");
     * System.out.println(hm.values());
     */
    public HashMap<String, String> getAttribut(final String actorsNamn) {
        return SQLSelectRow("select * from skadespelare "
                + "where skadespelare.namn = '" + actorsNamn + "'");
    }

    /**
     * Usage Example : Kombination av getSkadespelare och getAttribut
     * System.out.println(SQL.getSkadespelare().getAllAttribut());
     */
    public ArrayList<HashMap<String, String>> getAllAttribut() {
        return SQLSelectRows("select * from skadespelare");
    }
    
    /**
     * Usage Example : Se vilka förmågor en skådespelare har Variables used: hm
     * = HashMap HashMap<String, String> hm =
     * SQL.getSkadespelare().getFormagor("Ebba-Louise Flink");
     * System.out.println(Text.getSpecialCharacters(hm.get(Text.getSafeSpecialCharacters("namn"))
     * + ": " + hm.get(Text.getSafeSpecialCharacters("beskrivning"))));
     */
    public HashMap<String, String> getFormagor(String actorsName) {
        String query = "select skadespelare.namn, formaga.beskrivning from skadespelare "
                + "join skadespelare_har_formaga ON skadespelare.sid = skadespelare_har_formaga.sid "
                + "join formaga ON skadespelare_har_formaga.fid = formaga.fid "
                + "where skadespelare.namn = '" + actorsName + "';";
        
        return SQLSelectRow(query);
    }
    
    public ArrayList<String> getFormagorNamn(String actorsName) {
        String query = "select formaga.namn from formaga "
                + "join skadespelare_har_formaga ON formaga.fid = skadespelare_har_formaga.fid "
                + "join skadespelare ON skadespelare_har_formaga.sid = skadespelare.sid "
                + "where skadespelare.namn = '" + actorsName + "';";
        
        return SQLSelectList(query);
    }
    
    public ArrayList<String> getFormagorFromSID(int SID) {
        String query = "select formaga.namn from formaga " +
                "join skadespelare_har_formaga on formaga.fid=skadespelare_har_formaga.fid " + 
                "join skadespelare on skadespelare_har_formaga.sid=skadespelare.sid " +
                "where skadespelare.sid = " + SID;
        return SQLSelectList(query);
    }
    
    public ArrayList<String> getFormagorFromSkadespelare(String namn) {
        String query = "select formaga.namn from formaga " +
                "join skadespelare_har_formaga on formaga.fid=skadespelare_har_formaga.fid " + 
                "join skadespelare on skadespelare_har_formaga.sid=skadespelare.sid " +
                "where skadespelare.namn = '" + namn + "'";
        return SQLSelectList(query);
    }
    
    /*
     * getSkadespelareFromFID(Text.parseNumber(SQLSelect("select formaga.fid from formaga where formaga.namn = '" + f + "'")));
     */
    public ArrayList<String> getSkadespelareFromFID(int FID) {
        String query = "select skadespelare.namn from skadespelare " +
                "join skadespelare_har_formaga on skadespelare.sid=skadespelare_har_formaga.sid " + 
                "join formaga on skadespelare_har_formaga.fid=formaga.fid " +
                "where formaga.fid = " + FID;
        return SQLSelectList(query);
    }
    
    /*
     * System.out.println(SQL.getSkadespelare().getAllSkadespelareThatMatchesManyFID(new String[] {"namn", "name", "a name"}));
     */
    public ArrayList<String> getAllSkadespelareThatMatchesManyFID(String[] formagor) {
        int[] fids = new int[formagor.length];
        for (int i = 0; i<fids.length; i++) {
            fids[i] = Text.parseNumber(SQLSelect("select formaga.fid from formaga where formaga.namn = '" + formagor[i] + "'"));
        }
        return getAllSkadespelareThatMatchesManyFID(fids);
    }
    
    /*
     * System.out.println(SQL.getSkadespelare().getAllSkadespelareThatMatchesManyFID(new int[] {6, 5, 14}));
     */
    public ArrayList<String> getAllSkadespelareThatMatchesManyFID(int[] FID) {
        String FIDs = "";
        
        for (int fid : FID) {
            if (fid != FID[0]) {
                FIDs += ", " + fid;
            }
        }
        
        String query = "select sid from skadespelare_har_formaga where fid in (" + FID[0] + FIDs + ")";
        
        //######################## Testing code #######################
        
        //Sparar koden, det blir snabba och enkla vägen ut för den här gången.
        //if (FID.length > 1) { mode = "having"; }
        /*String mode = "where";
        for (int fid : FID) {
            if (fid == FID[0]) {
                FIDs += mode + " fid = '" + fid + "'";
            } else {
                FIDs += " or fid = '" + fid + "'";
            }
        }*/
        //query = "select SID from skadespelare_har_formaga " + FIDs;
        /*query = "select skadespelare_har_formaga.fid from skadespelare_har_formaga " +
                "inner join skadespelare_har_formaga setmp " +
                "on skadespelare_har_formaga.fid = temp.fid " + 
                "and skadespelare_har_formaga.sid != temp.sid " + 
                "where skadespelare_har_formaga.sid = 6";*/
        
        /*String query = "select skadespelare.namn from skadespelare " +
                "join skadespelare_har_formaga on skadespelare.sid=skadespelare_har_formaga.sid " + 
                "join formaga on skadespelare_har_formaga.fid=formaga.fid " +
                FIDs;*/
        
        //###############################################
        
        ArrayList<String> fidList = new ArrayList<String>();
        ArrayList<String> queryList = SQLSelectList(query);
        
        if (queryList != null) {
            for (String fid : queryList) {
                if (!(fidList.contains(fid))) {
                    fidList.add(fid);
                }
            }
        }
        
        return fidList;
    }

    /**
     * Usage Example : Se vilka roller en skådespelare tidigare innehaft
     * Variables used: alhm = ArrayListHashMap, hm = HashMap
     * ArrayList<HashMap<String, String>> alhm =
     * SQL.getSkadespelare().getRoller("Ebba-Louise Flink"); for
     * (HashMap<String, String> hm : alhm) { System.out.println(hm.values()); }
     */
    public ArrayList<HashMap<String, String>> getRollerExtra(String actorsName) {
        String query = "select roll.rid, roll.namn as rnamn from skadespelare "
                + "join roll on skadespelare.sid = roll.sid "
                + "where skadespelare.namn = '" + actorsName + "'";

        return SQLSelectRows(query);
    }
    
    /**
     * Usage Example : Se vilka roller en skådespelare tidigare innehaft
     * Variables used: alhm = ArrayListHashMap, hm = HashMap
     * ArrayList<HashMap<String, String>> alhm =
     * SQL.getSkadespelare().getRoller("Ebba-Louise Flink"); for
     * (HashMap<String, String> hm : alhm) { System.out.println(hm.values()); }
     */
    public ArrayList<String> getRoller(String actorsName) {
        String query = "select roll.namn from skadespelare "
                + "join roll on skadespelare.sid = roll.sid "
                + "where skadespelare.namn = '" + actorsName + "'";

        return SQLSelectList(query);
    }
    
    /**
     * Usage Example : Se vilka roller en skådespelare tidigare innehaft
     * Variables used: alhm = ArrayListHashMap, hm = HashMap
     * ArrayList<HashMap<String, String>> alhm =
     * SQL.getSkadespelare().getRoller("Ebba-Louise Flink"); for
     * (HashMap<String, String> hm : alhm) { System.out.println(hm.values()); }
     */
    public ArrayList<String> getRoller(int actorsID) {
        String query = "select roll.rid from skadespelare "
                + "join roll on skadespelare.sid = roll.sid "
                + "where skadespelare.sid = '" + actorsID + "'";

        return SQLSelectList(query);
    }

    /**
     * Usage Example : Se vilka roller en skådespelare tidigare föreslagits för
     * Names used: alhm = ArrayListHashMap, hm = hashMap
     * ArrayList<HashMap<String, String>> alhm =
     * SQL.getSkadespelare().getForslagenRoll("Ebba-Louise Flink"); for
     * (HashMap<String, String> hm : alhm) { System.out.println(hm.values()); }
     * Note: Felstavning på skadepelare_forslagen_roll > skade<s>pelare
     */
    public ArrayList<HashMap<String, String>> getForslagenRoll(String actorsName) {
        String query = "select skadespelare.namn, roll.namn as rnamn from skadespelare "
                + "join skadepelare_forslagen_roll on skadespelare.sid = skadepelare_forslagen_roll.sid "
                + "join roll on skadepelare_forslagen_roll.rid = roll.rid "
                + "where skadespelare.namn = '" + actorsName + "'";

        return SQLSelectRows(query);
    }

    /**
     * Usage Example : Se vilken agent som representerar en skådespelare
     * Variables used: s = String String s =
     * SQL.getSkadespelare().getAgent("Ebba-Louise Flink");
     * System.out.println(s);
     */
    public String getAgent(String actorsName) {
        String query = "select agent.namn from agent "
                + "join skadespelare on skadespelare.aid = agent.aid "
                + "where skadespelare.namn = " + actorsName;

        return SQLSelect(query);
    }

    /**
     * Usage Example : Se vilka produktioner en skådespelare jobbat med tidigare
     * Variables used: alhm = ArrayListHashMap, hm = HashMap
     * ArrayList<HashMap<String, String>> alhm =
     * SQL.getSkadespelare().getProduktioner("Ebba-Louise Flink"); for
     * (HashMap<String, String> hm : alhm) { System.out.println(hm.values()); }
     */
    public ArrayList<HashMap<String, String>> getProduktioner(String actorsName) {
        String query = "select roll.namn, produktion.titel from roll "
                + "join produktion on produktion.pid = roll.pid "
                + "join skadespelare on skadespelare.sid = roll.sid "
                + "where skadespelare.namn = '" + actorsName + "'";

        return SQLSelectRows(query);
    }

    /* for (String s : SQL.getSkadespelare().SokSkadespelare("", new IntPoints(-1, -1), -1, "", "", new IntPoints(-1, -1), new IntPoints(-1, -1), "")) {
     System.out.println(s);
     }
     */
    /**
     * Search for skådespelare in the database, empty strings and -1 on integers
     * will make it not to be searched for. All text is case insensitive. When
     * searching for a skådespelares name, you only have to search for a part of
     * it. For example first or surname to find person(s).
     *
     * @param namn skådespelarens namn
     * @param alder skådespelarens ålder new IntPoints(min, max)
     * @param kon skådespelarens kön
     * @param harfarg skådespelarens hårfärg
     * @param ogonfarg skadepselarens ögonfärg
     * @param langd skådespelarens längd
     * @param vikt skådespelarens vikt
     * @param formaga skådespelarens förmågas namn (Does not work at the moment)
     * @return lista över skådespelare som matchar sökningen
     */
    public ArrayList<String> SokSkadespelare(final String namn, final IntPoints alder, final int kon, final String harfarg, final String ogonfarg, final IntPoints langd, final IntPoints vikt, final String[] formagor) { //[7.1.1]
        String sql = ""; //The SQL query that is going to be executed.
        String andOrWhere = " where"; //Since you have to use "and" after the first "where" in SQL, we use a variable as an easy fix.

        /*
         if (!formaga.isEmpty()) {
         sql = " join skadespelare_har_formaga ON skadespelare.sid = skadespelare_har_formaga.sid" +
         " join formaga ON skadespelare_har_formaga.fid = formaga.fid" + 
         " where formaga.namn='" + formaga + "'";
         andOrWhere = " and";
         }
         */
        
        //sql = "join skadespelare_har_formaga ON skadespelare.sid = skadespelare_har_formaga.sid "
        //        + "join formaga ON skadespelare_har_formaga.fid = '" + SQLSelect("select formaga.fid from formaga where formaga.namn = '" + formagor[0] + "'") + "'";
        
        /*boolean formagorMatch = true; //True = inga förmågor hittade = "de matchar" eller förmågor matchar.
        for (String f : formagor) {
            System.out.println("Förmågor was found: " + f);
            if (f != null && !f.isEmpty()) {
                System.out.println("    - Not null");
                System.out.println("    - Not empty");
                if (!namn.isEmpty()) {
                    System.out.println("    - Name is not empty");
                    formagorMatch = false; //Förmågor hittade.
                    ArrayList<String> formagorList = getFormagorNamn(namn);
                    if (formagorList != null) {
                        for (String f2 : formagorList) {
                            if (f2.equalsIgnoreCase(namn)) {
                                formagorMatch = true;
                            }
                            else {
                                formagorMatch = false;
                                break; //Something didn't match, search exits.
                            }
                        }
                    }
                }
                else {
                    System.out.println("    - Name is empty");
                    System.out.println("        Looking for any skådespelare that match this förmåga.");
                    
                    System.out.println();
                    ArrayList<String> fList = getSkadespelareFromFID(Text.parseNumber(SQLSelect("select formaga.fid from formaga where formaga.namn = '" + f + "'")));
                    if (fList != null && !fList.isEmpty()) {
                        sql = " join skadespelare_har_formaga ON skadespelare.sid = skadespelare_har_formaga.sid" +
                        " join formaga ON skadespelare_har_formaga.fid = formaga.fid" + 
                        " where formaga.namn='" + f + "'";
                        andOrWhere = " and";
                    }
                    //TODO, this is not supported yet.
                    //What this function is going to do is to go through every variable and check if there is any variable that contains a value which it can use to check for a result.
                    //System.out.println("Unfinished function used in SokSkadespelare [ formagor ]. This function is unused.");
                }
            }
        }*/
        
        if (formagor != null && formagor.length > 0) {
            ArrayList<String> searchSkadespelare = getAllSkadespelareThatMatchesManyFID(formagor);
            boolean firstItemDone = false;
            String tmpSql = "";
            
            if (searchSkadespelare != null) {
                for (String idSkadespelare : searchSkadespelare) { //n = namn, id = id
                    boolean notFoundFormaga = false;
                    ArrayList<String> tmpTestFormagaSkadespelare = getFormagorFromSkadespelare(getSkadespelareNamn(Text.parseNumber(idSkadespelare)));
                    if (tmpTestFormagaSkadespelare != null) {
                        for (String nFormaga : formagor) {
                            if (!tmpTestFormagaSkadespelare.contains(nFormaga)) {
                                notFoundFormaga = true;
                                break;
                            }
                        }
                    }
                    
                    //All förmågor was found and not the first item.
                    if (!firstItemDone && !notFoundFormaga && !(searchSkadespelare.get(0).equalsIgnoreCase(idSkadespelare))) {
                        firstItemDone = true;
                        tmpSql += ", '" + getSkadespelareNamn(Text.parseNumber(idSkadespelare)) + "'";
                    }
                }

                sql += andOrWhere + " lower(namn) in ('" + getSkadespelareNamn(Text.parseNumber(searchSkadespelare.get(0))).toLowerCase() + "'" + tmpSql.toLowerCase() + ")";
                andOrWhere = " and";
            }
        }

        //Checking if values aren't empty, calculates and add it to the query.
        if (!namn.isEmpty()) {
            sql += andOrWhere + " lower(namn) like '%" + namn.toLowerCase() + "%'";
            andOrWhere = " and";
        }

        if (alder.min() >= 0) {
            sql += andOrWhere + " alder>=" + alder.x + " and alder<=" + alder.y;
            andOrWhere = " and";
        }

        if (kon >= 0) {
            sql += andOrWhere + " kon=" + kon;
            andOrWhere = " and";
        }

        if (!harfarg.isEmpty()) {
            sql += andOrWhere + " lower(harfarg)='" + harfarg.toLowerCase() + "'";
            andOrWhere = " and";
        }

        if (!ogonfarg.isEmpty()) {
            sql += andOrWhere + " lower(ogonfarg)='" + ogonfarg.toLowerCase() + "'";
            andOrWhere = " and";
        }

        if (langd.min() >= 0) {
            sql += andOrWhere + " langd>=" + langd.x + " and langd<=" + langd.y;
            andOrWhere = " and";
        }

        if (vikt.min() >= 0) {
            sql += andOrWhere + " vikt>=" + vikt.x + " and vikt<=" + vikt.y;
        }
        
        ArrayList<String> sNamnList = new ArrayList<String>();
        for (String sNamn : SQLSelectList("select namn from skadespelare" + sql + ";")) {
            if (!(sNamnList.contains(sNamn))) {
                sNamnList.add(sNamn);
            }
        }
        
        //System.out.println("select namn from skadespelare" + sql + ";");
        //System.out.println(SQLSelectList("select namn from skadespelare" + sql + ";"));
        return sNamnList;
    }
}
